﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Flee.PublicTypes;

namespace ComputeLib
{
    class CalculationAction : ICalculationAction
    {
        private ICalculation calculation;
        private Dictionary<string, object> varsValue = new Dictionary<string, object>();

        public CalculationAction(ICalculation calculation)
        {
            this.Calculation = calculation;
        }

        public ICalculation Calculation { get => calculation; set => calculation = value; }
        public Dictionary<string, object> VarsValue { get => varsValue; }

        public object calculate(Dictionary<string, object> vars)
        {
            List<String> inputVars = vars.Keys.ToList<String>();
            int dependentLength = calculation.DependentCaculations.Length;


            if (dependentLength == 0)
            {
                if (calculation.InputVars.Length != 0)
                {

                    //检查当前计算所需的变量，都包含在传入的参数中
                    List<String> calculationVars = calculation.InputVars.ToList();
                    Boolean containAll = true;
                    string lastVar = "";
                    for (int i = 0; i < inputVars.Count && containAll; i++)
                    {
                        containAll = containAll && calculationVars.Contains(inputVars[i]);
                        lastVar = inputVars[i];
                    }
                    if (!containAll)
                    {
                        string inputs = calculation.InputVars[0];
                        for (int i = 1; i < calculation.InputVars.Length; i++)
                        {
                            inputs += "," + calculation.InputVars[i];
                        }
                        String.Format("计算公式{0}传入参数有误，应传入参数包括:\"{1}\",实际缺少\"{2}\"", this.calculation.Name, inputs, lastVar);
                        Exception ex = new Exception("输入参数错误");
                        throw ex;
                    }
                }
                ExpressionContext context = new ExpressionContext();

                for (int i = 0; i < calculation.InputVars.Length; i++)
                {
                    string key = calculation.InputVars[i];
                    context.Variables.Add(key, vars[key]);
                }
                Flee.PublicTypes.IDynamicExpression expression = context.CompileDynamic(calculation.Formula);
                
                return expression.Evaluate();
            }
            else
            {

                //计算出所有依赖的表达式
                String[] dependentCaculations = calculation.DependentCaculations;
                
                for (int i = 0; i < dependentCaculations.Length; i++)
                {
                    CalculationAction calculationAction = createCalculation(dependentCaculations[i]);
                    VarsValue.Add(dependentCaculations[i], calculationAction.calculate(vars));
                }

                //输入参数传入VarsValue
                Dictionary<String,Object>.Enumerator enumerator =   vars.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    KeyValuePair<String,Object> keyValuePair =   enumerator.Current;
                    VarsValue.Add(keyValuePair.Key, keyValuePair.Value);
                }


                //将最终VarsValue的值传入表达式，计算出当前表达式的最终值
                ExpressionContext context = new ExpressionContext();
                enumerator = VarsValue.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    KeyValuePair<String, Object> keyValuePair = enumerator.Current;
                    context.Variables.Add(keyValuePair.Key, keyValuePair.Value);
                }

                Flee.PublicTypes.IDynamicExpression expression = context.CompileDynamic(calculation.Formula);
                return expression.Evaluate();

            }

        }

        private CalculationAction createCalculation(string name)
        {
            ICalculation calculation = Global.calculations.Find(c =>  c.Name.Equals(name));

            if (calculation != null)
            {
                CalculationAction calculationAction = new CalculationAction(calculation);
            
            }
            return null;
        }



    }
}
